/*-------------------------------------------------------------------------
 *
 * memnodes.h
 *	  POSTGRES 内存上下文节点定义。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/nodes/memnodes.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef MEMNODES_H
#define MEMNODES_H

#include "nodes/nodes.h"

/*
 * MemoryContextCounters
 *		内存上下文统计的汇总状态。
 *
 * 这个结构中的计数器集偏向于 AllocSet；如果我们将来
 * 添加任何基于根本不同方法的上下文类型，
 * 我们可能需要更多或不同的计数器。在那时，可能的 API 规范
 * 将是仅打印非零计数器，但目前我们只是使用 AllocSet
 * 过去使用的格式进行汇总。
 */
typedef struct MemoryContextCounters
{
	Size		nblocks;		/* malloc 块的总数量 */
	Size		freechunks;		/* free chunks 的总数量 */
	Size		totalspace;		/* 从 malloc 请求的总字节数 */
	Size		freespace;		/* totalspace 的未使用部分 */
} MemoryContextCounters;

/*
 * MemoryContext
 *		内存分配发生的逻辑上下文。
 *
 * MemoryContext 本身是一个抽象类型，可以有多个
 * 实现。
 * MemoryContextMethods 中的函数指针定义了 MemoryContext 的一个特定
 * 实现——它们在 C++ 中是一个虚函数表。
 *
 * 实际实现内存上下文的节点类型必须
 * 以与 MemoryContextData 相同的字段开始。
 *
 * 注意：出于历史原因，typedef MemoryContext 是一个指向上下文
 * 结构的指针，而不是结构类型本身。
 */

typedef void (*MemoryStatsPrintFunc) (MemoryContext context, void *passthru,
									  const char *stats_string,
									  bool print_to_stderr);

typedef struct MemoryContextMethods
{
	void	   *(*alloc) (MemoryContext context, Size size);
	/* 在某人 #define 的 free() 的情况下，调用此 free_p */
	void		(*free_p) (MemoryContext context, void *pointer);
	void	   *(*realloc) (MemoryContext context, void *pointer, Size size);
	void		(*reset) (MemoryContext context);
	void		(*delete_context) (MemoryContext context);
	Size		(*get_chunk_space) (MemoryContext context, void *pointer);
	bool		(*is_empty) (MemoryContext context);
	void		(*stats) (MemoryContext context,
						  MemoryStatsPrintFunc printfunc, void *passthru,
						  MemoryContextCounters *totals,
						  bool print_to_stderr);
#ifdef MEMORY_CONTEXT_CHECKING
	void		(*check) (MemoryContext context);
#endif
} MemoryContextMethods;


typedef struct MemoryContextData
{
	NodeTag		type;			/* 确定上下文的确切类型 */
	/* 这两个字段放在这里以最小化对齐浪费： */
	bool		isReset;		/* T = 自上次重置以来没有分配空间 */
	bool		allowInCritSection; /* 允许在关键区间进行 palloc */
	Size		mem_allocated;	/* 跟踪为此上下文分配的内存 */
	const MemoryContextMethods *methods;	/* 虚函数表 */
	MemoryContext parent;		/* 如果没有父级（顶级上下文），则为 NULL */
	MemoryContext firstchild;	/* 子节点的链表头 */
	MemoryContext prevchild;	/* 同一父级的前一个子级 */
	MemoryContext nextchild;	/* 同一父级的下一个子节点 */
	const char *name;			/* 上下文名称（仅用于调试） */
	const char *ident;			/* 如果有的话，上下文 ID（仅用于调试） */
	MemoryContextCallback *reset_cbs;	/* 重置/删除回调列表 */
} MemoryContextData;

/* utils/palloc.h 包含 typedef struct MemoryContextData *MemoryContext */


/*
 * MemoryContextIsValid
 *		当且仅当内存上下文有效时为真。
 *
 * 将新上下文类型添加到此宏接受的集合中。
 */
#define MemoryContextIsValid(context) \
	((context) != NULL && \
	 (IsA((context), AllocSetContext) || \
	  IsA((context), SlabContext) || \
	  IsA((context), GenerationContext)))

#endif							/* MEMNODES_H */
